import * as XLSX from "xlsx";
import * as FileSaver from "file-saver";
import QRCode from "qrcode";
import JSZip from "jszip";
import api from "./../api/api.js";

const base = {
  /**
   * 将数据转换成导出所需的格式
   * @param {Array} rawData 原始数据
   * @returns {Array} 转换后的数据
   */
  transformData(rawData) {
    const transformedData = [];

    // 按照年份倒序排序
    rawData.sort((a, b) => new Date(b.year) - new Date(a.year));

    rawData.forEach((sheetData) => {
      const data = sheetData.yearData.map((item, index) => {
        const month = new Date(item.month).toISOString().slice(0, 7); // 提取年和月
        const rank = `第${index + 1}名`;
        return {
          月份: index === 0 ? month : null, // 只有第一项显示月份
          名次: rank,
          部门: item.departmentName,
          姓名: item.name,
          有效隐患: `${item.valid_hazard_count}条`,
        };
      });
      transformedData.push(...data);
    });

    return transformedData;
  },

  /**
   * 导出提报之星
   * @param {*} title 厂别
   * @param {*} rawData 原始数据
   * @param {*} fileName 文件名称
   */
  ExportStart(title, rawData, fileName) {
    // 转换数据
    const data = this.transformData(rawData);

    // 创建工作簿和工作表
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet([
      [title, null, null, null, null],
      ["月份", "名次", "部门", "姓名", "有效隐患"],
      ...data.map((item) => [
        item.月份,
        item.名次,
        item.部门,
        item.姓名,
        item.有效隐患,
      ]),
    ]);

    // 合并单元格
    const merges = [
      { s: { r: 0, c: 0 }, e: { r: 0, c: 4 } }, // 合并第一行的1-5列
    ];

    // 动态合并月份列
    let startRow = 2;
    let currentMonthStart = startRow;
    for (let i = 0; i < data.length; i++) {
      if (data[i].月份 !== null) {
        if (i > 0) {
          merges.push({
            s: { r: currentMonthStart, c: 0 },
            e: { r: startRow - 1, c: 0 },
          });
        }
        currentMonthStart = startRow;
      }
      startRow++;
    }
    merges.push({
      s: { r: currentMonthStart, c: 0 },
      e: { r: startRow - 1, c: 0 },
    });

    ws["!merges"] = merges;

    // 添加工作表到工作簿
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");

    // 导出 Excel 文件
    XLSX.writeFile(wb, `${fileName}.xlsx`);
  },

  /**
   * 导出部门提报率
   * @param {*} dataList 需要导出的数据信息
   * @param {*} fileName 导出的文件名称
   */
  async exportAllData(dataList, fileName) {
    // 创建工作簿
    const wb = XLSX.utils.book_new();

    dataList.forEach((dataObj) => {
      const yearMonth = dataObj.yearMonth;
      const detailedData = dataObj.detailedData;

      // 创建工作表数据
      const ws_data = [
        ["参与对象", "类别"],
        ["部门所有人（包含外包）", "提报人数"],
        ["", "部门总人数"],
        ["", "提报率"],
      ];

      // 遍历数据数组并添加到工作表
      detailedData.forEach((item) => {
        ws_data[0].push(item.category || "");
        ws_data[1].push(item.reported || 0);
        ws_data[2].push(item.total || 0);
        ws_data[3].push(item.rate || 0);
      });

      // 创建工作表
      const ws = XLSX.utils.aoa_to_sheet(ws_data);
      ws["!merges"] = [
        { s: { r: 1, c: 0 }, e: { r: 3, c: 0 } }, // 合并第一列第2,3,4行
      ];

      // 添加工作表到工作簿
      const sheetName = `${yearMonth}-月度提报率`;
      XLSX.utils.book_append_sheet(wb, ws, sheetName);
    });

    // 导出Excel文件
    XLSX.writeFile(wb, fileName + ".xlsx");
  },

  /**
   *
   * @param {*} RateData 需要导出的数据
   * @param {*} name 导出的excel名称
   */
  async ExportImprovementRateData(RateData, name) {
    // 定义标题行
    const headers = [
      "部门",
      "已改善",
      "未改善",
      "改善率（百分比）",
      "提报人数",
    ];

    // 创建工作簿
    const wb = XLSX.utils.book_new();

    // 遍历每年的数据
    RateData.forEach((yearData) => {
      const sheetName = `${yearData.yearMonth}-改善率信息`;

      // 将数据转换为纵向排版
      const tableData = [
        [headers[0], ...yearData.detailedData.map((row) => row.departmentName)],
        [headers[1], ...yearData.detailedData.map((row) => row.improve_count)],
        [
          headers[2],
          ...yearData.detailedData.map((row) => row.no_Improve_count),
        ],
        [headers[3], ...yearData.detailedData.map((row) => row.improve_rate)],
        [headers[4], ...yearData.detailedData.map((row) => row.report_count)],
      ];

      // 创建工作表并添加数据
      const ws = XLSX.utils.aoa_to_sheet(tableData);
      XLSX.utils.book_append_sheet(wb, ws, sheetName);
    });

    // 导出 Excel 文件
    XLSX.writeFile(wb, name + ".xlsx");
  },

  /**
   *
   * @param {*} ExportData 需要导出的数据格式
   * @param {*} name 导出的文件名称
   */
  async ExportMothData(ExportData, name) {
    // 创建工作簿
    const wb = XLSX.utils.book_new();

    // 遍历每个部门的数据
    ExportData.forEach((department) => {
      const wsData = [
        ["Employee Monthly Reporting Rate"],
        ["Indicator Measurement", "", "Goal TimeLine"],
        ["item", "Definition"],
      ];

      // 添加动态数据
      department.data.forEach((item, index) => {
        wsData[2].push(item.month);
        wsData[3] = wsData[3] || [
          "Employee Reporting",
          "(Employee Reporting Number / All Employee Number)*100%",
        ];
        wsData[3].push(item.reportingEmployeeNumber);
        wsData[4] = wsData[4] || [
          "Employee Reporting",
          "(Employee Reporting Number / All Employee Number)*100%",
        ];
        wsData[4].push(item.employee);
        wsData[5] = wsData[5] || [
          "Employee Reporting",
          "(Employee Reporting Number / All Employee Number)*100%",
        ];
        wsData[5].push(item.percentage);
      });

      // 动态计算合并列数
      const colCount = wsData[2].length;

      // 填充第一行的空白单元格
      while (wsData[0].length < colCount) {
        wsData[0].push("");
      }

      const ws = XLSX.utils.aoa_to_sheet(wsData);

      // 合并单元格
      ws["!merges"] = [
        { s: { r: 0, c: 0 }, e: { r: 0, c: colCount - 1 } }, // 动态合并 Employee Monthly Reporting Rate
        { s: { r: 1, c: 0 }, e: { r: 1, c: 1 } }, // 合并 Indicator Measurement
        { s: { r: 1, c: 2 }, e: { r: 1, c: colCount - 1 } }, // 合并 Goal TimeLine
        { s: { r: 2, c: 0 }, e: { r: 2, c: 0 } }, // 合并 item
        { s: { r: 2, c: 1 }, e: { r: 2, c: 1 } }, // 合并 Definition
        { s: { r: 3, c: 0 }, e: { r: 5, c: 0 } }, // 合并 None1
        { s: { r: 3, c: 1 }, e: { r: 5, c: 1 } }, // 合并 None1
      ];

      // 添加工作表到工作簿
      XLSX.utils.book_append_sheet(wb, ws, department.departmentName);
    });

    // 导出 Excel 文件
    XLSX.writeFile(wb, name + ".xlsx");
  },
  /**
   * 批量生成二维码并下载
   * @param {*} Array 需要生成二维码的列表
   */
  async BatchGenerationQrcode(Array) {
    const zip = new JSZip();
    for (const item of Array) {
      const qrCodeDataUrl = await QRCode.toDataURL(
        this.CreateQrCode(item.LicensePlate)
      );
      const base64Data = qrCodeDataUrl.split(",")[1];
      zip.file(`${item.LicensePlate}.png`, base64Data, { base64: true });
    }
    const content = await zip.generateAsync({ type: "blob" });
    FileSaver(content, new Date().getTime() + "车辆二维码.zip");
  },
  /**
   * 二维码中的内容
   */
  async CreateQrCode(LicensePlate) {
    //改为动态的
    let key = ["二维码前缀内容"];
    let res = await api.GetVueDictionary(key);
    if (res.length > 0) {
      if (res[0].data.length > 0) {
        return res[0].data[0].value + LicensePlate;
      }
    }
  },
  isValidTimeFormat(input) {
    // 定义正则表达式，匹配格式为 HH:MM:SS-HH:MM:SS
    const regex =
      /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)-([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/;
    return regex.test(input);
  },

  /**
   * 导出普通excel文件
   * @param {*} val 需要导出的数据
   * @param {*} headers excel列
   * @param {*} ExcelName excel名称
   */
  exportToExcel(val, headers, ExcelName) {
    // 创建一个工作簿
    const workbook = XLSX.utils.book_new();

    // 创建一个工作表
    const worksheetData = [headers];

    // 将数据添加到工作表
    val.forEach((item) => {
      const row = headers.map((header) => item[header]);
      worksheetData.push(row);
    });

    const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);

    // 将工作表添加到工作簿中
    XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");

    // 生成 Excel 文件并触发下载
    const excelBuffer = XLSX.write(workbook, {
      bookType: "xlsx",
      type: "array",
    });

    const dataBlob = new Blob([excelBuffer], {
      type: "application/octet-stream",
    });

    FileSaver.saveAs(dataBlob, `${ExcelName}.xlsx`);
  },

  processData(rawData) {
    // 初始化数据结构
    const headers = ["线路名称"];
    const timeSlots = new Set();

    // 遍历原始数据，收集所有时间段
    rawData.forEach((item) => {
      if (item.workingTime) {
        timeSlots.add(item.workingTime);
      }
      if (item.closingTime) {
        timeSlots.add(item.closingTime);
      }
    });

    // 将时间段排序并添加到表头
    const sortedTimeSlots = Array.from(timeSlots).sort();
    sortedTimeSlots.forEach((timeSlot) => {
      headers.push(`${timeSlot}-等车人数`);
      headers.push(`${timeSlot}-派车数量`);
    });

    // 初始化数据数组
    const data = [headers];

    // 创建一个临时对象来存储每条线路的数据
    const tempData = {};

    // 遍历原始数据
    rawData.forEach((item) => {
      const routeName = item.routeName; // 使用整个字段作为路线名称
      const workingTime = item.workingTime; // 提取上班接时间
      const closingTime = item.closingTime; // 提取下班接时间
      const waitingNumber = item.waitingNumber; // 提取等车人数
      const needCarNumber = item.needCarNumber; // 提取派车数量

      // 初始化临时对象中的线路数据
      if (!tempData[routeName]) {
        tempData[routeName] = {};
        sortedTimeSlots.forEach((timeSlot) => {
          tempData[routeName][timeSlot] = {
            waitingNumber: 0,
            needCarNumber: 0,
          };
        });
      }

      // 更新临时对象中的数据
      if (workingTime) {
        if (!tempData[routeName][workingTime]) {
          tempData[routeName][workingTime] = {
            waitingNumber: 0,
            needCarNumber: 0,
          };
        }
        tempData[routeName][workingTime].waitingNumber += waitingNumber;
        tempData[routeName][workingTime].needCarNumber += needCarNumber;
      }
      if (closingTime) {
        if (!tempData[routeName][closingTime]) {
          tempData[routeName][closingTime] = {
            waitingNumber: 0,
            needCarNumber: 0,
          };
        }
        tempData[routeName][closingTime].waitingNumber += waitingNumber;
        tempData[routeName][closingTime].needCarNumber += needCarNumber;
      }
    });

    // 将临时对象中的数据转换为最终的数组格式
    for (const routeName in tempData) {
      const row = [routeName];
      sortedTimeSlots.forEach((timeSlot) => {
        row.push(tempData[routeName][timeSlot].waitingNumber);
        row.push(tempData[routeName][timeSlot].needCarNumber);
      });
      data.push(row);
    }

    return data;
  },

  expectPlus(val, ExcelName) {
    // 创建一个新的工作簿
    const wb = XLSX.utils.book_new();
    let data = this.processDataBack(val);
    // 将数据转换为工作表
    const ws = XLSX.utils.aoa_to_sheet(data);

    // 设置列宽
    const wscols = [
      { wch: 10 },
      { wch: 15 },
      { wch: 10 },
      { wch: 15 },
      { wch: 10 },
      { wch: 15 },
      { wch: 10 },
      { wch: 15 },
      { wch: 10 },
    ];
    ws["!cols"] = wscols;

    // 设置单元格合并
    const merges = [
      { s: { r: 1, c: 1 }, e: { r: 1, c: 2 } }, // 合并第2行的第2和第3列
      { s: { r: 1, c: 3 }, e: { r: 1, c: 4 } }, // 合并第2行的第4和第5列
      { s: { r: 1, c: 5 }, e: { r: 1, c: 6 } }, // 合并第2行的第6和第7列
      { s: { r: 1, c: 7 }, e: { r: 1, c: 8 } }, // 合并第2行的第8和第9列
      { s: { r: 1, c: 9 }, e: { r: 1, c: 10 } }, // 合并第2行的第8和第9列
      { s: { r: 1, c: 11 }, e: { r: 1, c: 12 } }, // 合并第2行的第8和第9列
      { s: { r: 1, c: 13 }, e: { r: 1, c: 14 } }, // 合并第2行的第8和第9列
      { s: { r: 1, c: 15 }, e: { r: 1, c: 16 } }, // 合并第2行的第8和第9列
    ];

    // 动态合并第一行的单元格并填写内容
    const firstRowMerges = [];
    let currentApplicationTime = null;
    let mergeStart = null;

    for (let i = 1; i < data[1].length; i += 2) {
      const applicationTime = data[1][i].split(" ")[0]; // 只取年月日
      if (currentApplicationTime === null) {
        currentApplicationTime = applicationTime;
        mergeStart = i;
      } else if (currentApplicationTime !== applicationTime) {
        if (mergeStart !== null && mergeStart < i - 1) {
          firstRowMerges.push({
            s: { r: 0, c: mergeStart },
            e: { r: 0, c: i - 1 },
          });
          const cellAddress = XLSX.utils.encode_cell({ r: 0, c: mergeStart });
          ws[cellAddress] = {
            v: currentApplicationTime,
            s: { alignment: { horizontal: "center", vertical: "center" } },
          };
        }
        currentApplicationTime = applicationTime;
        mergeStart = i;
      }
    }

    // 处理最后一组合并
    if (mergeStart !== null && mergeStart < data[1].length - 1) {
      firstRowMerges.push({
        s: { r: 0, c: mergeStart },
        e: { r: 0, c: data[1].length - 1 },
      });
      const cellAddress = XLSX.utils.encode_cell({ r: 0, c: mergeStart });
      ws[cellAddress] = {
        v: currentApplicationTime,
        s: { alignment: { horizontal: "center", vertical: "center" } },
      };
    }

    ws["!merges"] = merges.concat(firstRowMerges);

    // 设置单元格居中
    const cellStyle = {
      alignment: {
        horizontal: "center",
        vertical: "center",
      },
    };
    for (let i = 0; i < data.length; i++) {
      for (let j = 0; j < data[i].length; j++) {
        const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
        if (!ws[cellAddress]) ws[cellAddress] = {};
        ws[cellAddress].s = cellStyle;
      }
    }

    // console.log("book_append_sheet",ws)
    let result = this.removeDateFromMatchingObjects(ws);
    // 将工作表添加到工作簿
    XLSX.utils.book_append_sheet(wb, result, "Sheet1");

    // console.log("wb",wb)

    // 导出 Excel 文件
    XLSX.writeFile(wb, ExcelName + ".xlsx");
  },

  removeDateFromMatchingObjects(obj) {
    function search(obj) {
      if (Array.isArray(obj)) {
        obj.forEach((item) => search(item));
      } else if (typeof obj === "object" && obj !== null) {
        Object.entries(obj).forEach(([key, value]) => {
          if (typeof value === "object" && value !== null) {
            search(value);
          } else if (
            key === "v" &&
            typeof value === "string" &&
            value.includes("班接")
          ) {
            // 使用正则表达式去除年月日
            obj[key] = value.split(" ")[1];
          }
        });
      }
    }

    search(obj);
    return obj;
  },

  processDataBack(rawData) {
    // 初始化数据结构
    const applicationTimes = rawData.map(
      (item) => item.applicationTime.split(" ")[0]
    ); // 只取年月日
    const uniqueApplicationTimes = [...new Set(applicationTimes)].sort();
    // 动态生成时段数组
    const timeSlots = [
      ...new Set(
        rawData.flatMap((item) => [item.workingTime, item.closingTime])
      ),
    ].filter(Boolean);
    // 动态生成 headers
    const headers = [
      "",
      ...uniqueApplicationTimes.flatMap((time) =>
        timeSlots.flatMap((slot) => [`${time} ${slot}`, ""])
      ),
    ];

    // 动态生成 subHeaders
    const subHeaders = [
      "",
      ...uniqueApplicationTimes.flatMap(() =>
        timeSlots.flatMap(() => ["等车人数", "派车数量"])
      ),
    ];

    const data = [[" "], headers, subHeaders];

    // 创建一个临时对象来存储每条线路的数据
    const tempData = {};

    // 遍历原始数据
    rawData.forEach((item) => {
      const routeName = item.routeName; // 使用整个字段作为路线名称
      const workingTime = item.workingTime; // 提取上班接时间
      const closingTime = item.closingTime; // 提取下班接时间
      const waitingNumber = item.waitingNumber; // 提取等车人数
      const needCarNumber = item.needCarNumber; // 提取派车数量

      if (!tempData[routeName]) {
        tempData[routeName] = {};
        uniqueApplicationTimes.forEach((time) => {
          tempData[routeName][time] = {};
          timeSlots.forEach((slot) => {
            tempData[routeName][time][slot] = {
              waitingNumber: 0,
              needCarNumber: 0,
            };
          });
        });
      }

      // 更新临时对象中的数据
      if (workingTime) {
        tempData[routeName][item.applicationTime.split(" ")[0]][
          workingTime
        ].waitingNumber += waitingNumber;
        tempData[routeName][item.applicationTime.split(" ")[0]][
          workingTime
        ].needCarNumber += needCarNumber;
      }
      if (closingTime) {
        tempData[routeName][item.applicationTime.split(" ")[0]][
          closingTime
        ].waitingNumber += waitingNumber;
        tempData[routeName][item.applicationTime.split(" ")[0]][
          closingTime
        ].needCarNumber += needCarNumber;
      }
    });

    for (const routeName in tempData) {
      const row = [routeName];
      uniqueApplicationTimes.forEach((time) => {
        const timeSlots = tempData[routeName][time];
        for (const slot in timeSlots) {
          row.push(timeSlots[slot].waitingNumber);
          row.push(timeSlots[slot].needCarNumber);
        }
      });
      data.push(row);
    }

    return data;
  },
  formatDate(date) {
    const newDate = new Date(date);
    // 设置日期为前一天
    newDate.setDate(newDate.getDate() - 1);

    const year = newDate.getFullYear();
    const month = String(newDate.getMonth() + 1).padStart(2, "0");
    const day = String(newDate.getDate()).padStart(2, "0");
    const hours = String(newDate.getHours()).padStart(2, "0");
    const minutes = String(newDate.getMinutes()).padStart(2, "0");
    const seconds = String(newDate.getSeconds()).padStart(2, "0");
    const milliseconds = String(newDate.getMilliseconds()).padStart(3, "0");

    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}:${milliseconds}`;
  },
  isValidDateRange(startDate, endDate) {
    const start = new Date(startDate);
    const end = new Date(endDate);
    if (start > end) {
      return "开始时间晚于结束时间，不符合规范"; // 开始时间晚于结束时间，不符合规范
    }
    return ""; // 开始时间早于或等于结束时间，符合规范
  },
  getCurrentDate() {
    const today = new Date();
    const year = today.getFullYear();
    const month = today.getMonth() + 1; // 月份从0开始，所以需要加1
    const day = today.getDate();

    return `${year}-${month.toString().padStart(2, "0")}-${day
      .toString()
      .padStart(2, "0")}`;
  },
  addDays(date, days) {
    //给指定日期增加天数
    if (!days) {
      return date;
    }
    let dateArr = date.split(" ");
    date = new Date(new Date(date).setDate(new Date(date).getDate() + days));
    let year = date.getFullYear();
    let month = date.getMonth() + 1;
    if (month < 10) {
      month = "0" + month;
    }
    let day = date.getDate();
    if (day < 10) {
      day = "0" + day;
    }
    date = year + "-" + month + "-" + day;
    if (dateArr.length == 1) {
      return date;
    }
    return date + " " + dateArr[1];
  },
  //获取当前时间，time是否带时分秒
  getDate(time) {
    let date = new Date();
    let year = date.getFullYear();
    let month = date.getMonth() + 1;
    let day = date.getDate();

    let datetime =
      year +
      "-" +
      (month < 10 ? "0" + month : month) +
      "-" +
      (day < 10 ? "0" + day : day);

    if (!time) {
      return datetime;
    }

    let hour = date.getHours();
    let minutes = date.getMinutes();
    let second = date.getSeconds();

    return (
      datetime +
      "" +
      " " +
      (hour < 10 ? "0" + hour : hour) +
      ":" +
      (minutes < 10 ? "0" + minutes : minutes) +
      ":" +
      (second < 10 ? "0" + second : second)
    );
  },
  isPhone(val) {
    return /^[1][3,4,5,6,7,8,9]\d{9}$/.test(val);
  },
  isDecimal(val) {
    return /(^[\-0-9][0-9]*(.[0-9]+)?)$/.test(val);
  },
  isNumber(val) {
    return /(^[\-0-9][0-9]*([0-9]+)?)$/.test(val);
  },
  isMail(val) {
    return /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(val);
  },
  isUrl(url) {
    return this.checkUrl(url);
  },
  checkUrl(url) {
    // url= 协议://(ftp的登录信息)IP|域名(/或?请求参数)
    const strRegex =
      `^((https|http|ftp)://)?` + // (https或http或ftp):// 可有可无
      `(([\\w_!~*'()\\.&=+$%-]+: )?[\\w_!~*'()\\.&=+$%-]+@)?` + // ftp的user@  可有可无
      `(([0-9]{1,3}\\.){3}[0-9]{1,3}` + // IP形式的URL- 3位数字.3位数字.3位数字.3位数字
      `|` + // 允许IP和DOMAIN（域名）
      `(localhost)|` + // 匹配localhost
      `([\\w_!~*'()-]+\\.)*` + // 域名- 至少一个[英文或数字_!~*\'()-]加上.
      `\\w+\\.` + // 一级域名 -英文或数字  加上.
      `[a-zA-Z]{1,6})` + // 顶级域名- 1-6位英文
      `(:[0-9]{1,5})?` + // 端口- :80 ,1-5位数字
      `((/?)|` + // url无参数结尾 - 斜杆或这没有
      `(/[\\w_!~*'()\\.;?:@&=+$,%#-]+)+/?)$`; // 请求参数结尾- 英文或数字和[]内的各种字符

    const re = new RegExp(strRegex, "i"); // i不区分大小写

    // 将url做uri转码后再匹配，解除请求参数中的中文和空字符影响
    return !!re.test(encodeURI(url));
  },
  matchUrlIp(url, ip) {
    // url使用是否使用的当前ip
    if (!url || !ip) {
      return false;
    }
    return url.indexOf(ip.replace("https://", "").replace("http://", "")) >= 0;
  },
  getImgSrc(src, httpUrl) {
    if (this.isUrl(src)) {
      return src;
    }
    if (httpUrl) {
      return httpUrl + src;
    }
    return src;
  },
  previewImg(src, httpUrl) {
    // 图片预览，目前只支持单图片预览
    if (src && !this.isUrl(src) && httpUrl) {
      if (
        src.substr(0, 1) == "/" &&
        httpUrl.substr(httpUrl.length - 1, 1) == "/"
      ) {
        src = src.substr(1);
      }
      src = httpUrl + src;
    }
    let id = "vol-preview";
    let $div = document.getElementById(id);
    if (!$div) {
      $div = document.createElement("div");
      $div.setAttribute("id", "vol-preview");
      let $mask = document.createElement("div");
      $mask.style.position = "absolute";
      $mask.style.width = "100%";
      $mask.style.height = "100%";
      $mask.style.background = "black";
      $mask.style.opacity = "0.6";
      $div.appendChild($mask);
      $div.style.position = "fixed";
      $div.style.width = "100%";
      $div.style.height = "100%";
      // $div.style.overflow = "scroll";
      $div.style.top = 0;
      $div.style["z-index"] = 9999999;
      let $img = document.createElement("img");
      $img.setAttribute("class", "vol-preview-img");
      $img.style.position = "absolute";
      $img.style.top = "50%";
      $img.style.left = "50%";
      $img.style["max-width"] = "90%";
      $img.style["max-height"] = "90%";
      $img.style.transform = "translate(-50%,-50%)";
      // $img.src = src;
      $img.setAttribute("src", src);
      $div.appendChild($img);
      $div.addEventListener("click", function () {
        this.style.display = "none";
      });
      document.body.appendChild($div);
      return;
    }
    let $img1 = document.body
      .appendChild($div)
      .querySelector(".vol-preview-img");
    // img.src = src;
    $img1.setAttribute("src", src);
    $div.style.display = "block";
  },
  // 下载文件 $element 标签, url完整url, fileName 文件名, header 以key/value传值
  // backGroundUrl 后台url，如果后台url直接从后台下载，其他全部通过点击a标签下载
  dowloadFile(url, fileName, header, backGroundUrl) {
    if (!url) return alert("此文件没有url不能下载");
    if (!this.isUrl(url)) {
      url = backGroundUrl + url;
    }
    window.open(url);
  },
  downloadImg(data) {
    if (!data.url || !data.callback || typeof data.callback !== "function") {
      return;
    }
    // url, backGroundUrl, header, callback
    if (
      this.isUrl(data.url) &&
      !this.matchUrlIp(data.url, data.backGroundUrl)
    ) {
      return data.url;
    }
    // 通过后台api服务器下载
    if (!this.isUrl(data.url)) {
      if (!this.isUrl(data.backGroundUrl + data.url)) {
        return;
      }
      data.url = data.backGroundUrl + data.url;
    }
    let xmlResquest = new XMLHttpRequest();
    xmlResquest.open("get", data.url, true);
    xmlResquest.responseType = "blob";
    xmlResquest.setRequestHeader("Content-Type", "application/json");
    if (data.header && typeof data.header === "object") {
      for (const key in data.header) {
        xmlResquest.setRequestHeader(key, data.header[key]);
      }
    }
    xmlResquest.onload = function () {
      if (this.status == 200) {
        let blob = this.response;
        callback(window.URL.createObjectURL(blob));
      }
    };
    xmlResquest.send();
  },
  // 2020.06.01增加通用方法，将普通对象转换为tree结构
  // data数据格式[
  //     { name: 'tree1', id: 1, parentId: 0 },
  //     { name: 'tree2', id: 2, parentId: 0 }]

  // 1、id与parentId这两个字段必须有
  // 2、树形tree需要注意Id与parentId循环依赖的问题
  // 3、callback每次生成一新的节点的时回调的方法

  convertTree(data, callback) {
    let treeIds = [];
    let root_data = [];
    if (data.length > 100) {
      data = JSON.parse(JSON.stringify(data));
    }
    data.forEach((x) => {
      if (
        !x.hidden &&
        x.id !== undefined &&
        x.id !== x.parentId &&
        !data.some((s) => x.parentId === s.id)
      ) {
        x.isRoot = true;
        if (callback) callback(x, data, true, treeIds);
        root_data.push(x);
        getTree(x.id, x, data, callback, treeIds);
      } else if (callback) {
        callback(x, data, true, treeIds);
      }
    });
    let exceptionNodes = data.filter((f) => {
      return treeIds.indexOf(f.id) == -1 && !f.hidden;
    });

    root_data.push(...exceptionNodes);
    return root_data;
  },
  getTreeAllParent(id, data) {
    // 获取某个节点的所有父节点信息2020.11.01
    let nodes = [];
    if (!(data instanceof Array)) {
      return nodes;
    }
    if (data.length > 100) {
      data = JSON.parse(JSON.stringify(data));
    }
    data.forEach((x) => {
      const { id, parentId } = x;
      if (
        id === parentId ||
        data.some((c) => c.parentId === id && c.id === parentId)
      ) {
        x.parentId = 0;
      }
    });

    let _child = data.find((x) => {
      return x.id === id;
    });
    if (!_child) {
      return [];
    }
    nodes.push(_child);
    let _parentIds = [_child.parentId];
    for (const element of _parentIds) {
      let _node = data.find((x) => {
        return x.id === element && x.id !== x.parentId;
      });
      if (!_node) {
        return nodes;
      }
      _parentIds.push(_node.parentId);
      nodes.unshift(_node);
    }
    return nodes;
  },
  //获取所有节点的子节点
  // data数据格式[
  //     { name: 'tree1', id: 1, parentId: 0 },
  //     { name: 'tree2', id: 2, parentId: 0 }]
  getTreeAllChildren(id, data) {
    //递归获取某个节点的所有子节点信息
    let nodes = [];
    if (!(data instanceof Array)) {
      return nodes;
    }
    if (data.length > 100) {
      data = JSON.parse(JSON.stringify(data));
    }
    let _child = data.find((x) => {
      return x.id === id;
    });
    if (!_child) {
      return [];
    }
    nodes.push(_child);
    let _parentIds = [_child.id];
    for (const element of _parentIds) {
      data.forEach((_node) => {
        if (_node.parentId === element && _node.parentId !== _node.id) {
          _parentIds.push(_node.id);
          nodes.unshift(_node);
        }
      });
    }
    return nodes;
  },
  //获取所有子节点的id
  // data数据格式[
  //     { name: 'tree1', id: 1, parentId: 0 },
  //     { name: 'tree2', id: 2, parentId: 0 }]
  getTreeAllChildrenId(id, data) {
    return this.getTreeAllChildren(id, data).map((c) => {
      return c.id;
    });
  },
};
export default base;

// 2020.06.01增加通用方法，将普通对象转换为tree结构
function getTree(id, node, data, callback, treeIds = new Set()) {
  if (treeIds.indexOf(id) == -1) {
    treeIds.push(id);
  }
  data.forEach((x) => {
    if (!x.hidden && x.parentId === id) {
      if (!node.children) node.children = [];
      if (callback) callback(x, node, false);
      node.children.push(x);
      getTree(x.id, x, data, callback, treeIds);
    }
  });
}
